<?php


namespace app\api\service;


use app\api\model\Dish;
use app\api\model\OrdersDish;
use app\lib\enum\OrdersStatusEnum;
use app\lib\exception\OrderException;
use think\Db;
use think\Exception;

class Orders
{
    // 客户端传递的商品列表信息
    protected $oProducts;
    // 数据库查询的商品信息
    protected $products;
    protected $uid;

    // 下单
    public function place($uid, $oProducts)
    {
        $this->oProducts = $oProducts; //订单商品（包含id，价格等数组）
        $this->products = $this->getDishByOrder($oProducts); //真实的数据库查询的商品
        $this->uid = $uid;
        // 记录getOrderStatus的结果
        $status = $this->getOrderStatus();
        if (!$status['pass']) {
            $status['orders_id'] = -1;
            return $status;
        }
        // 创建订单
        $ordersSnap = $this->snapOrders($status);
        $orders = $this->createOrders($ordersSnap);
        $orders['pass'] = true;
        return $orders;
    }

    // 创建订单
    private function createOrders($snap)
    {
        // 开始事务
        Db::startTrans();
        try {
            $ordersCode = $this->makeOrdersCode();
            $orders = new \app\api\model\Orders();
            $orders->openid = $this->uid;
            $orders->orders_code = $ordersCode;

            $orders->orders_price = $snap['ordersPrice'];
            $orders->orders_num = $snap['totalCount'];
            $orders->snap_img = $snap['snapImg'];
            $orders->snap_name = $snap['snapName'];
            $orders->snap_items = json_encode($snap['dStatus']);

            // 写入
            $orders->save();

            $ordersID = $orders->id;
            // 对数组里的orders_id做修改（需&）
            foreach ($this->oProducts as &$d) {
                $d['orders_id'] = $ordersID;
            }

            $create_time = $orders->create_time;

            $ordersDish = new OrdersDish();
            $oDish = $this->oProducts;
            $ordersDish->isUpdate(false)->saveAll($oDish, false);


            $order = \app\api\model\Orders::where('orders_code', '=', $ordersCode)
                ->find();
            if ($order->orders_state == OrdersStatusEnum::unPaid) {
                $service = new Orders();
                $status = $service->checkDishNum($order->id);
                $ordersState = new WxNotify();
                if ($status['pass']) {
                    $ordersState->updateOrdersState($order->id, true);
                    $ordersState->reduceDishNum($status);
                } else {
                    $ordersState->updateOrdersState($order->id, false);
                }
            }

            // 结束事务
            Db::commit();
            return [
                'orders_id' => $ordersID,
                'orders_code' => $ordersCode,
                'create_time' => $create_time
            ];
        } catch (Exception $e) {
            // 回滚撤销
            Db::rollback();
            throw $e;
        }

    }

    // 订单号
    public static function makeOrdersCode()
    {
        $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'J');
        $ordersCode =
            $yCode[intval(date('Y')) - 2020]
            .strtoupper(dechex(date('m')))
            .date('d')
            .substr(time(), -5)
            .substr(microtime(), 2, 5)
            .sprintf('%02d', rand(0, 99));
        return $ordersCode;
    }

    // 生成订单快照
    private function snapOrders($status)
    {
        $snap = [
            'ordersPrice' => 0,
            'totalCount' => 0,
            'dStatus' => [],
            'snapName' => '',
            'snapImg' => ''
        ];
        // 赋值
        $snap['ordersPrice'] = $status['ordersPrice'];
        $snap['totalCount'] = $status['totalCount'];
        $snap['dStatus'] = $status['dStatusArray'];
        $snap['snapName'] = $this->products[0]['dish_name'];
        $snap['snapImg'] = $this->products[0]['dish_images'];

        if (count($this->products) > 1) {
            $snap['snapName'] .= '等';
        }

        return $snap;
    }

    // 支付时检查库存量
    public function checkDishNum($ordersID)
    {
        // 客户端提交商品
        $oProducts = OrdersDish::where('orders_id', '=', $ordersID)->select();
        $this->oProducts = $oProducts;

        // 数据库有的商品
        $this->products = $this->getDishByOrder($oProducts);

        $status = $this->getOrderStatus();
        return $status;
    }

    // 订单
    private function getOrderStatus()
    {
        // 订单状态
        $status = [
            'pass' => true,
            // 订单总价
            'ordersPrice' => 0,
            'totalCount' => 0,
            // 保存全部订单详细信息
            'dStatusArray' => []
        ];
        // 比较oProducts和products确认库存
        foreach ($this->oProducts as $oProduct) {
            $dStatus = $this->getDishStatus(
                $oProduct['dish_id'], $oProduct['order_count'], $this->products
            );
            // 没有库存，订单不通过
            if (!$dStatus['haveDishNum']) {
                $status['pass'] = false;
            }
            $status['ordersPrice'] += $dStatus['totalPrice'];
            $status['totalCount'] += $dStatus['order_count'];
            array_push($status['dStatusArray'], $dStatus);
        }
        return $status;
    }

    // 订单里的商品
    private function getDishStatus($oDID, $oCount, $products)
    {
        // 确认当前商品在订单里的索引
        $dIndex = -1;

        // 订单里商品信息
        $dStatus = [
            'id' => null,
            'haveDishNum' => false, //库存
            'order_count' => 0, // 订单里商品购买数量
            'dish_name' => '',
            'totalPrice' => 0 //订单里某商品总价
        ];

        for ($i=0; $i<count($products); $i++) {
            // 当前商品和订单里的第i号商品一致
            if ($oDID == $products[$i]['id']) {
                $dIndex = $i;
            }
        }

        if ($dIndex == -1) {
            // 客户端传递的dish_id不存在
            throw new OrderException([
                'msg' => '没有id为'.$oDID.'的商品，订单创建失败'
            ]);
        } else {
            $product = $products[$dIndex];
            $dStatus['id'] = $product['id'];
            $dStatus['dish_name'] = $product['dish_name'];
            $dStatus['order_count'] = $oCount;
            $dStatus['totalPrice'] = $product['dish_nprice'] * $oCount;
            if ($product['dish_num'] - $oCount >= 0) {
                $dStatus['haveDishNum'] = true;
            }
        }

        return $dStatus;
    }

    // 根据订单查找真实商品信息
    private function getDishByOrder($oProducts)
    {
        // 遍历oProducts，不能直接循环查询数据库
        $oDIDs = [];

        foreach($oProducts as $item){
            array_push($oDIDs, $item['dish_id']);
        }
        // 查询数据库
        $products = Dish::all($oDIDs)
            ->visible(['id', 'dish_cate', 'dish_images', 'dish_name', 'dish_gprice', 'dish_nprice', 'dish_num'])
            ->toArray();
        return $products;
    }
}